#include	"alp_global_vars.h"
#include	"config_parser.h"

config_info *config_info_sample = NULL;

config_info * get_config_info() {
	return config_info_sample;
}

void parse_configuration(const char * config_path, int acceptor_id, int proposer_id, int learner_id) {
	char flag;
	char *match;
	config_info_sample = malloc(sizeof(config_info));
	assert(config_info_sample != NULL);

	config_info_sample->self_acceptor_id = (node_id_t) acceptor_id;
	config_info_sample->self_proposer_id = (node_id_t) proposer_id;
	config_info_sample->self_learner_id = (node_id_t) learner_id;

	match = "acceptor";
	flag = 'a';
	get_ip_port(config_path, get_config_info(), match, flag);

	match = "learner";
	flag = 'l';
	get_ip_port(config_path, get_config_info(), match, flag);

	match = "num_proposers";
	read_a_number(config_path, get_config_info(), match);

	//	match = "learner_to_acceptor";
	//	flag = 't';
	//	get_ip_port(config_path, get_config_info(), match, flag);

	config_info_sample->ring_size = config_info_sample->total_num_acceptors + config_info_sample->total_num_learners;

	create_socket_acceptor_ring(config_info_sample);

}
void read_a_number(const char* config_file, config_info * config, const char * match) {
	FILE * fp;
	char line[STRING_SIZE];
	char word[STRING_SIZE];
	int last_index = -1;

	fp = fopen(config_file, "r");
	assert(fp != NULL);

	while (!feof(fp)) {
		if (fgets(line, STRING_SIZE, fp) != 0) {
			last_index = get_substr(0, strlen(line) - 1, line, word);

			if (strcmp(word, match) == 0) {
				last_index = get_substr(last_index + 1, strlen(line) - 1, line, word);
				config->total_num_proposers = atoi(word);
			}
		}
	}
}
void get_ip_port(const char* config_file, config_info * config, const char * match, char flag) {

	FILE * fp;
	char line[STRING_SIZE];
	char word[STRING_SIZE];
	int last_index = -1, node_counter = 0;
	int learner_id, acceptor_id, la_port;

	fp = fopen(config_file, "r");
	assert(fp != NULL);
	while (!feof(fp)) {
		if (fgets(line, STRING_SIZE, fp) != 0) {
			last_index = get_substr(0, strlen(line) - 1, line, word);

			if (strcmp(word, match) == 0) {

				last_index = get_substr(last_index + 1, strlen(line) - 1, line, word);
				if (flag == 'a')
					config->server_infos[node_counter].server_id = (node_id_t) atoi(word);
				else if (flag == 't')
					learner_id = (node_id_t) atoi(word);
				else if (flag == 'l')
					config->learner_infos[node_counter].learner_id = (node_id_t) atoi(word);

				last_index = get_substr(last_index + 1, strlen(line) - 1, line, word);
				if (flag == 'a')
					memcpy(config->server_infos[node_counter].ip, word, strlen(word));
				else if (flag == 't')
					acceptor_id = (node_id_t) atoi(word);
				else if (flag == 'l')
					memcpy(config->learner_infos[node_counter].ip, word, strlen(word));

				last_index = get_substr(last_index + 1, strlen(line) - 1, line, word);
				if (flag == 'a')
					config->server_infos[node_counter].port = atoi(word);
				else if (flag == 't')
					la_port = atoi(word);
				else if (flag == 'l')
					config->learner_infos[node_counter].port = atoi(word);

				if (flag == 't') {
					config->server_infos[acceptor_id].learner_tcp_acceptor[node_counter].acceptor_id = acceptor_id;
					config->server_infos[acceptor_id].learner_tcp_acceptor[node_counter].learner_id = learner_id;
					config->server_infos[acceptor_id].learner_tcp_acceptor[node_counter].acceptor_port = la_port;
				}

				node_counter++;
			}
		}
	}
	if (flag == 'a')
		config->total_num_acceptors = node_counter;
	else if (flag == 'p')
		config->total_num_proxies = node_counter;
	else if (flag == 'l')
		config->total_num_learners = node_counter;

	fclose(fp);
}
void create_socket_acceptor_ring(config_info *config) {

	int successor_id = config->self_acceptor_id + 1;
	int self_id = config->self_acceptor_id;

	//	config->server_infos[self_id].self_sid = create_udp_server_socket(config->server_infos[self_id].ip, config->server_infos[self_id].port, &(config->server_infos[self_id].ring_self_addr));
	//	config->server_infos[config->self_acceptor_id].successor_sid = create_udp_client_socket(config->server_infos[successor_id].ip, config->server_infos[successor_id].port, &(config->server_infos[self_id].ring_successor_addr));

	if (self_id == 0) {
		printf("Creating socket to send msg to successor on the ring ip: %s port: %d\n", config->server_infos[successor_id].ip, config->server_infos[successor_id].port);
		config->server_infos[self_id].successor_sid = create_tcp_client_socket(config->server_infos[successor_id].ip, config->server_infos[successor_id].port);
		printf("SOCKET: %d\n", config->server_infos[self_id].successor_sid);
		printf("Creating socket to receive msg on the ring ip: %s port: %d\n", config->server_infos[self_id].ip, config->server_infos[self_id].port);
		config->server_infos[self_id].self_sid = create_tcp_server_socket(config->server_infos[self_id].ip, config->server_infos[self_id].port);
	} else {
		config->server_infos[self_id].self_sid = create_tcp_server_socket(config->server_infos[self_id].ip, config->server_infos[self_id].port);

		if (config->self_acceptor_id == config->total_num_acceptors - 1) { // this acceptor will connect to the 0th learner
			successor_id = 0;
			printf("Creating socket to send msg to successor on the ring ip: %s port: %d\n", config->learner_infos[successor_id].ip, config->learner_infos[successor_id].port);
			config->server_infos[config->self_acceptor_id].successor_sid = create_tcp_client_socket(config->learner_infos[successor_id].ip, config->learner_infos[successor_id].port);
			//printf("Creating socket to send msg to successor on the ring ip: %s port: %d\n", config->server_infos[successor_id].ip, config->server_infos[successor_id].port);
			//config->server_infos[config->self_acceptor_id].successor_sid = create_tcp_client_socket(config->server_infos[successor_id].ip, config->server_infos[successor_id].port);

		} else {
			printf("Creating socket to send msg to successor on the ring ip: %s port: %d\n", config->server_infos[successor_id].ip, config->server_infos[successor_id].port);
			config->server_infos[self_id].successor_sid = create_tcp_client_socket(config->server_infos[successor_id].ip, config->server_infos[successor_id].port);
		}

	}

}
void create_socket_for_acceptor_tcp_learner(config_info *config) {
	a_create_tcp_server_socket_4_learners(config->server_infos[config->self_acceptor_id].learner_tcp_acceptor[0].acceptor_port, config->server_infos[config->self_acceptor_id].ip, config->self_acceptor_id);
}
int find_learner_given_ip(config_info *config, char ip[INET_ADDRSTRLEN]) {
	int i = 0;

	for (i = 0; i < config->total_num_learners; i++) {
		if (strcmp(ip, config->learner_infos[i].ip) == 0) {
			return (int) config->learner_infos[i].learner_id;
		}
	}

	return -1;
}
int find_learner_index_given_id(config_info *config, int learner_id, int server_id) {
	int i = 0;

	for (i = 0; i < config->learner_tcp_sid_count; i++) {
		if (learner_id == (int) config->server_infos[server_id].learner_tcp_acceptor[i].learner_id) {
			return i;
		}
	}
	return -1;
}

//-------ACCEPTOR-----------------------------------
int GET_ACCEPTOR_SELF_SID_RING(int id) {
	return config_info_sample->server_infos[id].self_sid;
}
int GET_ACCEPTOR_SUCCESSOR_SID_RING(int id) {
	return config_info_sample->server_infos[id].successor_sid;
}
int GET_ACCEPTOR_0_SID_UDP_FROM_PROPOSER(int id) {
	return config_info_sample->server_infos[id].proposer_recv_sid;
}
int GET_ACCEPTOR_SID_TCP_FROM_LEARNER(int server_id, int nth_learner) {
	return config_info_sample->server_infos[server_id].learner_tcp_acceptor[nth_learner].learner_tcp_sid;
}
int GET_ACCEPTOR_SID_UDP_TO_LEARNER_0(int id) {
	return config_info_sample->server_infos[id].send_learner_0_sid;
}
//-------LEARNER------------------------------------
int GET_LEARNER_SID_TCP_TO_ACCEPTOR() {
	return config_info_sample->learner_to_acceptor_sid;
}
//-------PROPOSER------------------------------------
int GET_PROPOSER_SID_UDP_TO_ACCEPTOR_0(int id) {
	return config_info_sample->proposer_infos[id].proposer_to_acceptor_0_sid;
}
